package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
    @Autowired
    WemediaFeign wemediaFeign;
    @Autowired
    ArticleFeign articleFeign;

    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    @Value("${file.oss.web-site}")
    private String webSite;

    @Autowired
    GreenTextScan greenTextScan;
    @Autowired
    GreenImageScan greenImageScan;
    @Autowired
    AdChannelMapper adChannelMapper;
    @Autowired
    private KafkaTemplate kafkaTemplate;

    /**
     * 自媒体文章审核
     *
     * @param wmNewsId
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //参数校验
        if (wmNewsId == null) {
            log.error("当前的审核ID不能为空");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //1 根据文章id查询wmNews数据
        WmNews wmNews = wemediaFeign.findOne(wmNewsId);
        if (wmNews == null || wmNews.getStatus() == null) {
            log.error("审核的自媒体文章不存在，自媒体的id:{}", wmNewsId);
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2 判断文章状态=4 (人工审核通过)且发布时间小于等于当前时间,直接发布文章(保存三张表)
        if (wmNews.getStatus().shortValue() == WmNews.Status.ADMIN_SUCCESS.getCode()
                && wmNews.getPublishTime().getTime() <= new Date().getTime()) {
            publishArticle(wmNews);
            return;
        }
        //3 判断文章状态=8 (审核通过) 且发布时间小于等于当前时间,直接发布文章(保存三张表)
        if (wmNews.getStatus().shortValue() == WmNews.Status.SUCCESS.getCode()
                && wmNews.getPublishTime().getTime() <= new Date().getTime()) {
            publishArticle(wmNews);
            return;
        }
        //4 判断文章状态=1 (待审核状态) 根据审核的结果修改wmNews的 status\reason\article_id
        if (wmNews.getStatus().shortValue() == WmNews.Status.SUBMIT.getCode()) {
            //4.0 处理文章内容中的文本和图片
            Map<String, Object> map = handleTextAndImages(wmNews);
            String content = (String) map.get("content");
            List images = (List) map.get("images");

            //4.1 审核文章: 自管理敏感词
            boolean sensitiveScan = handleSensitive(content, wmNews);
            if (!sensitiveScan) {
                return;
            }
            //4.2 审核文章: 阿里云内容反垃圾审核(block/review/pass)
            boolean aliyunTextScan = handleAliyunText(wmNews, content);
            if (!aliyunTextScan) {
                return;
            }
            //4.3 审核文章: 阿里云图片审核
            boolean aliyunImageScan = handleAliyunImages(wmNews, images);
            if (!aliyunImageScan) {
                return;
            }
        }
        //5 审核通过,判断当前文章的发布时间是否大于当前时间(还未到发布时间),设置状态8
        if (wmNews.getPublishTime().getTime() > new Date().getTime()) {
            updateWmNews(wmNews, 8, "审核通过待发布");
            return;
        }
        //发布时间已过,直接发布
        publishArticle(wmNews);
    }

    /**
     * 发布文章(保存三张表)
     *
     * @param wmNews
     */
    private Long publishArticle(WmNews wmNews) {
        //远程调用保存app文章三张表数据 id存入result的data
        ResponseResult result = saveArticle(wmNews);
        if (result.getCode().intValue() != 0) {
            CustException.cust("保存app失败");
        }
        wmNews.setArticleId((Long) result.getData());
        updateWmNews(wmNews, 9, "已发布");

        //发送消息,生成文章静态页面(异步)
        Map<String, Long> map = new HashMap<>();
        map.put(NewsAutoScanConstants.ARTICLE_ID, wmNews.getArticleId());
        kafkaTemplate.send(NewsAutoScanConstants.GENERATE_PAGE_TOPIC, JSON.toJSONString(map));
        //返回articleId
        return wmNews.getArticleId();
    }

    /**
     * 远程调用保存app文章三张表数据 id存入result的data
     *
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        //dto参数设置
        BeanUtils.copyProperties(wmNews, dto);
        dto.setId(wmNews.getArticleId());
        //dto文章作者设置
        WmUser wmUser = wemediaFeign.findById(wmNews.getUserId());
        if (wmUser == null || wmUser.getStatus().intValue() != 9) {
            CustException.cust("当前自媒体用户已被禁用");
        }
        dto.setAuthorName(wmUser.getName());
        //dto频道设置
        AdChannel adChannel = adChannelMapper.selectById(wmNews.getChannelId());
        if (adChannel == null || adChannel.getName() == null) {
            CustException.cust("此频道不存在");
        }
        dto.setChannelId(adChannel.getId());
        dto.setChannelName(adChannel.getName());
        //dto其他参数设置
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);
        dto.setLikes(0);
        dto.setCollection(0);
        dto.setComment(0);
        dto.setViews(0);
        dto.setCreatedTime(new Date());
        dto.setSyncStatus(true);
        dto.setOrigin(true);
        dto.setContent(wmNews.getContent());
        //远程调用 保存文章三张表数据, data 设置成功保存后的APP文章ID
        return articleFeign.saveArticle(dto);
    }

    /**
     * 4.3 审核文章: 阿里云图片审核
     *
     * @param wmNews
     * @param images
     * @return
     */
    private boolean handleAliyunImages(WmNews wmNews, List images) {
        try {
            Map map = greenImageScan.imageUrlScan(images);
            if (map.get("suggestion").equals("block")) {
                //审核失败
                log.error("阿里云审核: 图片涉嫌违规");
                updateWmNews(wmNews, 2, "阿里云审核: 图片涉嫌违规");
                return false;
            }
            if (map.get("suggestion").equals("review")) {
                //需要人工审核
                log.error("阿里云审核: 图片需要人工审核");
                updateWmNews(wmNews, 3, "阿里云审核: 图片需要人工审核");
                return false;
            }

        } catch (Exception e) {
            log.error("阿里云审核失败,图片需要人工介入审核");
            updateWmNews(wmNews, 3, "阿里云审核失败,图片需要人工介入审核");
            return false;

        }
        return true;
    }

    /**
     * 4.2 审核文章: 阿里云内容反垃圾审核(block/review/pass)
     *
     * @param content
     * @return
     */
    private boolean handleAliyunText(WmNews wmNews, String content) {
        try {
            Map map = greenTextScan.greenTextScan(content);
            if (map.get("suggestion").equals("block")) {
                //审核失败
                log.error("阿里云审核: 文章中存在敏感词");
                updateWmNews(wmNews, 2, "阿里云审核: 文章中存在敏感词");
                return false;
            }
            if (map.get("suggestion").equals("review")) {
                //需要人工审核
                log.error("阿里云审核: 文章需要人工审核");
                updateWmNews(wmNews, 3, "阿里云审核: 文章需要人工审核");
                return false;
            }

        } catch (Exception e) {
            log.error("阿里云审核失败,文章需要人工介入审核");
            updateWmNews(wmNews, 3, "阿里云审核失败,文章需要人工介入审核");
            return false;

        }
        return true;
    }

    /**
     * 4.1 审核文章: 自管理敏感词
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        //先查询出来
        List<String> sensitives = adSensitiveMapper.findSensitives();
        //判断文章是否存在敏感词
        SensitiveWordUtil.initMap(sensitives);
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            //存在敏感词,修改wmNews状态为审核失败
            log.error("文章中存在敏感词" + map);
            updateWmNews(wmNews, 2, "文章中存在敏感词" + map);
            return false;
        }
        return true;
    }

    /**
     * 修改自媒体文章状态
     *
     * @param wmNews
     * @param status
     * @param msg
     */
    private void updateWmNews(WmNews wmNews, int status, String msg) {
        wmNews.setStatus(status);
        wmNews.setReason(msg);
        //审核通过才能有app文章id
        ResponseResult result = wemediaFeign.updateWmNews(wmNews);
        if (result.getCode().intValue() != 0) {
            CustException.cust("修改自媒体文章状态失败");
        }
    }


    /**
     * //4.0 处理文章内容中的文本和图片
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //参数校验
        String content = wmNews.getContent();
        if (StringUtils.isBlank(content) || content.length() > 10000) {
            log.warn("文章内容不合法");
            CustException.cust("文章内容不合法");
        }
        List<Map> contentList = JSON.parseArray(content, Map.class);
        //解析文本文字
        String contents = contentList.stream()
                .filter(x -> x.get("type").equals("text"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.joining("_"));
        //加上标题一起检测(省钱)
        contents = wmNews.getTitle() + "_" + contents;
        //解析文本图片
        List<String> images = contentList.stream()
                .filter(x -> x.get("type").equals("image"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.toList());
        //加上标题图片
        String imageCover = wmNews.getImages();
        if (imageCover != null) {
            images.addAll(Stream.of(imageCover.split(","))
                    .map(x -> webSite + x)
                    .collect(Collectors.toList()));
        }
        //图片去重(省钱)
        images = images.stream().distinct().collect(Collectors.toList());
        //封装返回
        Map<String, Object> map = new HashMap<>();
        map.put("content", contents);
        map.put("images", images);
        return map;
    }
}
